package core;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import interfaces.IAnswerManager;
import interfaces.IJob;
import interfaces.IJobManager;
import interfaces.IManagerProxy;
import interfaces.IStatusManager;

public class AnswerManager extends Thread implements IAnswerManager {

	// Define um procurador para o gerente
	private IManagerProxy managerProxy;
	
	// Define o gerente de tarefas
	private IJobManager jobManager;
	
	// Define o gerente de estado
	private IStatusManager statusWorkerManager;

	// Lista(mapa) de respostas de tarefas
	BlockingDeque<IJob> answerList;

	// Lista de mapas do pai dos jobs, armazena como chave o ID so sub-job e
	// valor o ID do job(pai)
	private Map<String, IJob> parentJobList;
	
	// Lista de tarefas enviados
	private Map<String, IJob> sendJobsList;

	// Define uma tarefa
	private IJob job, j;
	
	// Define o pai de uma tarefa;
	private IJob parentJob;
	
	// Define o identificador do gerente
	private String managerId;
	
	// Define a descricao da tarefa
	private byte resultDescr[];
	
	private boolean running = true;
	
	public AnswerManager() {
		try {
			// Instancia uma nova lista bloqueante de respostas de tarefas
			this.answerList = new LinkedBlockingDeque<IJob>();
		
			// Instancia uma nova lista para armazenar o pai de uma tarefa
			this.parentJobList = Collections.synchronizedMap(new LinkedHashMap<String, IJob>());

			// Instancia uma nova lista para armazenar as tarefas enviadas aos trablahadores
			this.sendJobsList = Collections.synchronizedMap(new LinkedHashMap<String, IJob>());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void run () {
		try {
			while(this.running) {
				this.j = this.answerList.take();
				this.resultDescr = this.j.getResultDescription();
				//this.workerId = this.j.getWorkerIdSolvedJob();
				
				//this.job = this.jobManager.getSendJobList(this.j.getID());
				this.job = this.getSendJobList(this.j.getID());
				this.job.setResultDescription(this.resultDescr);
				
				// /////////////////////////////////////////////////////////////////
				System.out.println("AnswerManager (" + this.getID() + ") =>");
				System.out.println("\t\t RECEBI JOB_RESULT: " + this.job.getID());
				System.out.println("\t\t JOBPAI: " + this.job.getParentJob() + "\n");
				// /////////////////////////////////////////////////////////////////

				if (!this.job.isRemote()) {
					if (this.job.isSolved()) {

						// /////////////////////////////////////////////////////////////////
						// System.out.println("AnswerManager (" + this.getID() + ") =>");
						// System.out.println("\t\t JOB ESTAH RESOLVIDO: " + this.job.getID());
						// System.out.println("\t\t JOBPAI: " + job.getParentJob() + "\n");
						// /////////////////////////////////////////////////////////////////

						if (this.job.getParentJob() != null) {
							//this.parentJob = this.jobManager.getParentJobList(this.job.getParentJob());
							this.parentJob = this.getParentJobList(this.job.getParentJob());
							this.parentJob.setResultDescription(this.job.getResultDescription());
							this.parentJob.setSubJobCount(1);
							if (this.parentJob.isSolved()) {
								// /////////////////////////////////////////////////////////////////
								// System.out.println("AnswerManager (" + this.getID() + ") =>");
								// System.out.println("\t\t JOBPAI ESTAH RESOLVIDO: " + job.getParentJob() + "\n");
								// /////////////////////////////////////////////////////////////////
								//this.jobManager.setSendJobList(this.job.getParentJob(), this.parentJob);
								this.setSendJobList(this.job.getParentJob(), this.parentJob);
								this.answerList.put(this.parentJob);
								//this.jobResult(this.workerId, this.parentJob.getID(), this.parentJob.getResultDescription());
							} else {
								//this.jobManager.setParentJobList(this.job.getParentJob(), this.parentJob);
								this.setParentJobList(this.job.getParentJob(), this.parentJob);
							}
						} else {
							// /////////////////////////////////////////////////////////////////
							System.out.println("AnswerManager (" + this.getID() + ") =>");
							System.out.println("\t\t TODAS AS RESPOSTAS DE " + this.job.getID() + "\n");
							// /////////////////////////////////////////////////////////////////
							this.getManagerProxy().resultSend(this.getID(), this.job.getID(), this.job.getResultDescription());
							//this.statusWorkerManager.reduceManagerWorkload(this.job.getWorkload());
							this.getStatusManager().reduceManagerWorkload(this.job.getWorkload());
						}
					} else {
						System.out.println("AnswerManager (" + this.getID() + ") =>");
						System.out.println("JOB NAO ESTAO RESOLVIDO \n");
					}
				} else {
					System.out.println("AnswerManager (" + this.getID()	+ ") =>");
					System.out.println("JOB EH REMOTO");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void jobResult(String workerId, String jobId, byte[] resultDescription) {
		// TODO Auto-generated method stub
		try {
			IJob job = new Fibo(workerId, resultDescription);
			job.setID(jobId);
			this.answerList.put(job);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void setID(String id) {
		// TODO Auto-generated method stub
		this.managerId = id;
	}

	@Override
	public String getID() {
		// TODO Auto-generated method stub
		return this.managerId;
	}
	
	@Override
	public synchronized void setParentJobList(String jobId, IJob job) {
		// TODO Auto-generated method stub
		try {
			this.parentJobList.put(jobId, job);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public synchronized IJob getParentJobList(String jobId) {
		// TODO Auto-generated method stub
		try {
			return this.parentJobList.remove(jobId);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	@Override
	public synchronized void setSendJobList(String jobId, IJob job) {
		try {
			this.sendJobsList.put(jobId, job);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public synchronized IJob getSendJobList(String jobId){
		try {
			return this.sendJobsList.remove(jobId);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public IManagerProxy getManagerProxy() {
		// TODO Auto-generated method stub
		return this.managerProxy;
	}

	@Override
	public void setManagerProxy(IManagerProxy managerProxy) {
		// TODO Auto-generated method stub
		this.managerProxy = managerProxy;
	}

	@Override
	public IJobManager getJobManager() {
		// TODO Auto-generated method stub
		return this.jobManager;
	}

	@Override
	public void setJobManager(IJobManager jobManager) {
		// TODO Auto-generated method stub
		this.jobManager = jobManager;
	}

	@Override
	public IStatusManager getStatusManager() {
		// TODO Auto-generated method stub
		return this.statusWorkerManager;
	}

	@Override
	public void setStatusMManager(IStatusManager statusManager) {
		// TODO Auto-generated method stub
		this.statusWorkerManager = statusManager;
	}
}